﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace DevToolBox.Common
{
    /// <summary>
    /// Class to write messages to a log file
    /// </summary>
    /// <remarks>
    /// This class is not thread-safe
    /// </remarks>
    public class FileLogger : ILogger
    {
        private readonly string ELAPSED_TIME_MSG = "Secs Elapsed: ";
        private string logPath = null;
        private string prevDayPath = null;
        private DateTime startDate;
        private bool loggingEnabled = false;
        private int retryTimes = 3;
        private int curRetires = 0;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="basePath">File path to write to</param>
        /// <param name="newLoggingEnabled">True to write the log file</param>
        public FileLogger(int tenantId, string basePath, bool newLoggingEnabled)
        {
            loggingEnabled = newLoggingEnabled;
            if (loggingEnabled)
            {
                logPath = basePath + DateTime.Now.ToString(DateTimeFormat.SHORT_DATE_FORMAT) + 
                          "_Tenant_" + tenantId + "_log.txt";
                prevDayPath = basePath + DateTime.Now.AddDays(-1).ToString(DateTimeFormat.SHORT_DATE_FORMAT) + 
                              "_Tenant_" + tenantId + "_log.txt";                
            }
        }

        /// <summary>
        /// Signals the start of an operation
        /// </summary>
        private void SetStart()
        {
            startDate = DateTime.UtcNow;
        }

        public void Write(string source, string message, ConsoleColor color, int messageId, string contextData = null)
        {
            SetStart();

            try
            {
                if (loggingEnabled)
                {
                    string content = "[" + source + "] [" + DateTime.Now.ToString(DateTimeFormat.LONG_TIME_FORMAT) +
                                     "] [" + message + "]";
                    if (messageId != SearchConstants.NOT_FOUND)
                    {
                        content += "[ID: " + messageId + " ]";
                    }

                    if (contextData != null)
                    {
                        content += "[ContextData: " + contextData + " ]";
                    }

                    if (color == ConsoleColor.Red)
                    {
                        content += "[Error: " + contextData + " ]";
                    }

                    Console.ForegroundColor = color;
                    Console.WriteLine(message);

                    bool isFileToBeCreated = !File.Exists(logPath);
                    if (isFileToBeCreated)
                    {
                        //We scheduled a delayed deletion
                        DeleteFileDelayed(prevDayPath, 1800);
                    }

                    var fs = new FileStream(logPath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite,
                                            4096, FileOptions.SequentialScan);
                    var sw = new StreamWriter(fs);
                    sw.WriteLine(content);
                    sw.Flush();
                    fs.Close();
                    fs.Dispose();
                }
            }
            catch (Exception ex)
            {
                if (curRetires <= retryTimes)
                {
                    curRetires++;
                    Write(source, message, color, messageId, contextData);
                }
            }
            curRetires = 0;
        }

        /// <summary>
        /// Function to delete a file after X seconds
        /// </summary>
        private static void DeleteFileDelayed(string fileToDelete, int seconds)
        {
            if (File.Exists(fileToDelete))
            {
                var Info = new System.Diagnostics.ProcessStartInfo();
                Info.Arguments = "/C choice /C Y /N /D Y /T " + seconds + " & Del " +
                                 fileToDelete;
                Info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                Info.CreateNoWindow = true;
                Info.FileName = "cmd.exe";
                System.Diagnostics.Process.Start(Info);
            }
        }

        /// <summary>
        /// Function to write messages to a log file
        /// and signaling the end of an operation
        /// </summary>
        /// <param name="message">Message to write</param>
        /// <param name="color">Color (i.e.: priority)</param>
        public void WriteTimeElapsed(string source, ConsoleColor color)
        {
            TimeSpan readEnd = DateTime.UtcNow -startDate;
            Write(source, ELAPSED_TIME_MSG + readEnd.TotalSeconds.ToString(), color, SearchConstants.NOT_FOUND);
            SetStart();
        }

    }
}
